﻿ /**
* @class BubbleChart
* @author InfoSoft Global (P) Ltd. www.InfoSoftGlobal.com
* @version 3.0
*
* Copyright (C) InfoSoft Global Pvt. Ltd. 2005-2006
*
* BubbleChart chart extends the XYPlotChart class to render a
* bubble chart.
*/
//Import Chart class
import com.fusioncharts.core.Chart;
//Parent XYPlotChart Class
import com.fusioncharts.core.XYPlotChart;
//Error class
import com.fusioncharts.helper.FCError;
//Import Logger Class
import com.fusioncharts.helper.Logger;
//Style Object
import com.fusioncharts.core.StyleObject;
//Delegate
import mx.utils.Delegate;
//Legend Class
import com.fusioncharts.helper.Legend;
//Extensions
import com.fusioncharts.extensions.ColorExt;
import com.fusioncharts.extensions.StringExt;
import com.fusioncharts.extensions.MathExt;
import com.fusioncharts.extensions.DrawingExt;
class com.fusioncharts.core.charts.BubbleChart extends XYPlotChart 
{
	//Version number (if different from super Chart class)
	//private var _version:String = "3.0.0";
	//Instance variables
	//List of chart objects
	private var _arrObjects : Array;
	private var xmlData : XML;
	/**
	* Constructor function. We invoke the super class'
	* constructor and then set the objects for this chart.
	*/
	function BubbleChart (targetMC : MovieClip, depth : Number, width : Number, height : Number, x : Number, y : Number, debugMode : Boolean, lang : String)
	{
		//Invoke the super class constructor
		super (targetMC, depth, width, height, x, y, debugMode, lang);
		//Log additional information to debugger
		//We log version from this class, so that if this class version
		//is different, we can log it
		this.log ("Version", _version, Logger.LEVEL.INFO);
		this.log ("Chart Type", "Bubble Chart", Logger.LEVEL.INFO);
		//List Chart Objects and set them
		_arrObjects = new Array ("BACKGROUND", "CANVAS", "CAPTION", "SUBCAPTION", "YAXISNAME", "XAXISNAME", "DIVLINES", "VLINES", "YAXISVALUES", "HGRID", "DATALABELS", "DATAVALUES", "TRENDLINES", "VTRENDLINES", "VTRENDVALUES", "TRENDVALUES", "DATAPLOT", "TOOLTIP", "LEGEND");
		super.setChartObjects (_arrObjects);
	}
	/**
	* render method is the single call method that does the rendering of chart:
	* - Parsing XML
	* - Calculating values and co-ordinates
	* - Visual layout and rendering
	* - Event handling
	*/
	public function render () : Void 
	{
		//Parse the XML Data document
		this.parseXML ();
		//Now, if the number of data elements is 0, we show pertinent
		//error.
		if (this.numDS * this.num == 0)
		{
			tfAppMsg = this.renderAppMessage (_global.getAppMessage ("NODATA", this.lang));
			//Add a message to log.
			this.log ("No Data to Display", "No data was found in the XML data document provided. Possible cases can be: <LI>There isn't any data generated by your system. If your system generates data based on parameters passed to it using dataURL, please make sure dataURL is URL Encoded.</LI><LI>You might be using a Single Series Chart .swf file instead of Multi-series .swf file and providing multi-series data or vice-versa.</LI>", Logger.LEVEL.ERROR);
		} else 
		{
			//Detect number scales
			this.detectNumberScales ();
			//Calculate the axis limits
			this.calculateAxisLimits ();
			//Calculate exact number of div lines
			this.calcDivs ();
			//Set Style defaults
			this.setStyleDefaults ();
			//Validate trend lines
			this.validateTrendLines ();
			//Allot the depths for various charts objects now
			this.allotDepths ();
			//Calculate Canvas Co-ordinates
			this.calcCanvasCoords ();
			//Calculate Points
			this.calculatePoints ();
			//Calculate trend line positions
			this.calcTrendLinePos ();
			//Feed macro values
			super.feedMacros ();
			//Remove application message
			this.removeAppMessage (this.tfAppMsg);
			//Set tool tip parameter
			this.setToolTipParam ();
			//-----Start Visual Rendering Now------//
			//Draw background
			this.drawBackground ();
			//Set click handler
			this.drawClickURLHandler ();
			//Load background SWF
			this.loadBgSWF ();
			//Update timer
			this.timeElapsed = (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.BACKGROUND) : 0;
			//Draw canvas
			this.config.intervals.canvas = setInterval (Delegate.create (this, drawCanvas) , this.timeElapsed);
			//Draw headers
			this.config.intervals.headers = setInterval (Delegate.create (this, drawHeaders) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.CANVAS, this.objects.CAPTION, this.objects.SUBCAPTION, this.objects.YAXISNAME, this.objects.XAXISNAME) : 0;
			//Draw div lines
			this.config.intervals.divLines = setInterval (Delegate.create (this, drawDivLines) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.DIVLINES, this.objects.YAXISVALUES) : 0;
			//Horizontal grid
			this.config.intervals.hGrid = setInterval (Delegate.create (this, drawHGrid) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation && (this.params.showAlternateHGridColor) ? this.styleM.getMaxAnimationTime (this.objects.HGRID) : 0);
			//Vertical lines
			this.config.intervals.vLine = setInterval (Delegate.create (this, drawVLines) , this.timeElapsed);
			//Draw trend lines
			this.config.intervals.vTrend = setInterval (Delegate.create (this, drawVTrendLines) , this.timeElapsed);
			this.config.intervals.trend = setInterval (Delegate.create (this, drawTrendLines) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.VLINES, this.objects.TRENDLINES, this.objects.VTRENDLINES, this.objects.TRENDVALUES) : 0;
			//Draw labels
			this.config.intervals.labels = setInterval (Delegate.create (this, drawLabels) , this.timeElapsed);
			//Legend
			this.config.intervals.legend = setInterval (Delegate.create (this, drawLegend) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation && this.styleM.getMaxAnimationTime (this.objects.DATALABELS, this.objects.LEGEND));
			//Bubbles
			this.config.intervals.bubbles = setInterval (Delegate.create (this, drawBubbleChart) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.DATAPLOT) : 0;
			//Data Values
			this.config.intervals.dataValues = setInterval (Delegate.create (this, drawValues) , this.timeElapsed);
			//Render context menu
			//We do not put context menu interval as we need the menu to appear
			//right from start of the play.
			this.setContextMenu ();
		}
	}
	/**
	* returnDataAsObject method creates an object out of the parameters
	* passed to this method. The idea is that we store each data point
	* as an object with multiple (flexible) properties. So, we do not
	* use a predefined class structure. Instead we use a generic object.
	*	@param	xv			x-Value for the data.
	*	@param	yv			y-Value for the data.
	*	@param	zv			z-Value for the data.
	*	@param	label		Label for the data
	*	@param	toolText	Tool tip text (if specified).
	*	@param	link		Link (if any) for the data.
	*	@param	showValue	Flag to show/hide value for this data.
	*	@param	color		color of the specific bubble
	*	@param	alpha		alpha of the specific bubble
	*	@return			An object encapsulating all these properies.
	*/
	private function returnDataAsObject (xv : Number, yv : Number, zv : Number, label : String, toolText : String, link : String, showValue : Number, color : String, alpha : Number) : Object 
	{
		//Create a container
		var dataObj : Object = new Object ();
		//Store the values
		dataObj.xv = xv;
		dataObj.yv = yv;
		dataObj.zv = zv;
		dataObj.name = label;
		dataObj.toolText = toolText;
		dataObj.link = link;
		dataObj.showValue = (showValue == 1) ? true : false;
		//If the given number is not a valid number or it's missing
		//set appropriate flags for this data point
		dataObj.isDefined = (isNaN (xv) || isNaN (yv) || isNaN (zv)) ? false : true;
		//Other parameters
		//X & Y Position of data point
		dataObj.x = 0;
		dataObj.y = 0;
		//X & Y Position of value tb
		dataObj.valTBX = 0;
		dataObj.valTBY = 0;
		//cosmetic properties
		dataObj.color = color;
		dataObj.alpha = alpha;
		//Return the container
		return dataObj;
	}
	/**
	* returnDataAsCat method returns data of a <category> element as
	* an object
	*	@param	label		Label of the category.
	*	@param	xv			X-value of the category
	*	@param	showLabel	Whether to show the label of this category.
	*	@param	toolText	Tool-text for the category
	*	@param	showLine	Whether to show vertical line
	*	@param	lineDashed	Whether vertical line is dashed
	*	@return			A container object with the given properties
	*/
	private function returnDataAsCat (label : String, xv : Number, showLabel : Number, toolText : String, showLine : Boolean, lineDashed : Boolean) : Object 
	{
		//Create container object
		var catObj : Object = new Object ();
		catObj.label = label;
		catObj.xv = xv;
		catObj.showLabel = ((showLabel == 1) && (label != undefined) && (label != null) && (label != "")) ? true : false;
		catObj.toolText = toolText;
		catObj.showLine = showLine;
		catObj.lineDashed = lineDashed;
		//X and Y Position
		catObj.x = 0;
		catObj.y = 0;
		//Valid
		catObj.isValid = true;
		//Return container
		return catObj;
	}
	/**
	* parseXML method parses the XML data, sets defaults and validates
	* the attributes before storing them to data storage objects.
	*/
	private function parseXML () : Void 
	{
		//Get the element nodes
		var arrDocElement : Array = this.xmlData.childNodes;
		//Loop variable
		var i : Number;
		var j : Number;
		var k : Number;
		//Look for <graph> element
		for (i = 0; i < arrDocElement.length; i ++)
		{
			//If it's a <graph> element, proceed.
			//Do case in-sensitive mathcing by changing to upper case
			if (arrDocElement [i].nodeName.toUpperCase () == "GRAPH" || arrDocElement [i].nodeName.toUpperCase () == "CHART")
			{
				//Extract attributes of <graph> element
				this.parseAttributes (arrDocElement [i]);
				//Now, get the child nodes - first level nodes
				//Level 1 nodes can be - CATEGORIES, DATASET, TRENDLINES, STYLES etc.
				var arrLevel1Nodes : Array = arrDocElement [i].childNodes;
				var setNode : XMLNode;
				//Iterate through all level 1 nodes.
				for (j = 0; j < arrLevel1Nodes.length; j ++)
				{
					if (arrLevel1Nodes [j].nodeName.toUpperCase () == "CATEGORIES")
					{
						//Categories Node.
						var categoriesNode : XMLNode = arrLevel1Nodes [j];
						//Convert attributes to array
						var categoriesAtt : Array = this.getAttributesArray (categoriesNode);
						//Extract attributes of this node.
						this.params.catFont = getFV (categoriesAtt ["font"] , this.params.outCnvBaseFont);
						this.params.catFontSize = getFN (categoriesAtt ["fontsize"] , this.params.outCnvBaseFontSize);
						this.params.catFontColor = formatColor (getFV (categoriesAtt ["fontcolor"] , this.params.outCnvBaseFontColor));
						//Category vertical lines
						this.params.catVerticalLineColor = formatColor (getFV (categoriesAtt ["verticallinecolor"] , this.defColors.get2DDivLineColor (this.params.palette)));
						trace (this.params.catVerticalLineColor);
						this.params.catVerticalLineThickness = getFN (categoriesAtt ["verticallinethickness"] , 1);
						this.params.catVerticalLineAlpha = getFN (categoriesAtt ["verticallinealpha"] , this.defColors.get2DDivLineAlpha (this.params.palette));
						this.params.catVerticalLineDashed = toBoolean (getFN (categoriesAtt ["verticallinedashed"] , 0));
						this.params.catVerticalLineDashLen = getFN (categoriesAtt ["verticallinedashlen"] , 4);
						this.params.catVerticalLineDashGap = getFN (categoriesAtt ["verticallinedashgap"] , 2);
						//Get reference to child node.
						var arrLevel2Nodes : Array = arrLevel1Nodes [j].childNodes;
						//Iterate through all child-nodes of CATEGORIES element
						//and search for CATEGORY or VLINE node
						for (k = 0; k < arrLevel2Nodes.length; k ++)
						{
							if (arrLevel2Nodes [k].nodeName.toUpperCase () == "CATEGORY")
							{
								//Category Node.
								//Update counter
								this.numCat ++;
								//Extract attributes
								var categoryNode : XMLNode = arrLevel2Nodes [k];
								var categoryAtt : Array = this.getAttributesArray (categoryNode);
								//Category label.
								var catLabel : String = getFV (categoryAtt ["label"] , categoryAtt ["name"] , "");
								//X-value
								var catX : Number = this.getSetValue (categoryAtt ["x"]);
								var catShowLabel : Number = getFN (categoryAtt ["showlabel"] , categoryAtt ["showname"] , this.params.showLabels);
								var catToolText : String = getFV (categoryAtt ["tooltext"] , categoryAtt ["hovertext"] , catLabel);
								var catShowLine : Boolean = toBoolean (getFN (categoryAtt ["showverticalline"] , categoryAtt ["sl"] , 0));
								var catLineDashed : Boolean = toBoolean (getFN (categoryAtt ["linedashed"] , this.params.catVerticalLineDashed));
								//If x value for category has has not been provided, we won't add it
								if (isNaN (catX))
								{
									this.numCat --;
								} else 
								{
									//Store it in data container.
									this.categories [this.numCat] = this.returnDataAsCat (catLabel, catX, catShowLabel, catToolText, catShowLine, catLineDashed);
								}
							}
						}
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "DATASET")
					{
						//Increment
						this.numDS ++;
						//Dataset node.
						var dataSetNode : XMLNode = arrLevel1Nodes [j];
						//Get attributes array
						var dsAtts : Array = this.getAttributesArray (dataSetNode);
						//Create storage object in dataset array
						this.dataset [this.numDS] = new Object ();
						//Store attributes
						this.dataset [this.numDS].seriesName = getFV (dsAtts ["seriesname"] , "");
						this.dataset [this.numDS].color = formatColor (getFV (dsAtts ["color"] , this.defColors.getColor ()));
						this.dataset [this.numDS].alpha = getFN (dsAtts ["plotfillalpha"] , dsAtts ["bubblefillalpha"] , this.params.plotFillAlpha);
						this.dataset [this.numDS].showValues = toBoolean (getFN (dsAtts ["showvalues"] , dsAtts ["showvalue"] , this.params.showValues));
						this.dataset [this.numDS].includeInLegend = toBoolean (getFN (dsAtts ["includeinlegend"] , 1));
						//Data set plot properties
						this.dataset [this.numDS].showPlotBorder = toBoolean (getFN (dsAtts ["showplotborder"] , this.params.showPlotBorder));
						this.dataset [this.numDS].plotBorderColor = formatColor (getFV (dsAtts ["plotbordercolor"] , dsAtts ["bubblebordercolor"] , this.params.plotBorderColor));
						this.dataset [this.numDS].plotBorderThickness = getFN (dsAtts ["plotborderthickness"] , dsAtts ["bubbleborderthickness"] , this.params.plotBorderThickness);
						this.dataset [this.numDS].plotBorderAlpha = (this.dataset [this.numDS].showPlotBorder) ? getFN (dsAtts ["plotborderalpha"] , dsAtts ["bubbleborderalpha"] , this.params.plotBorderAlpha) : 0;
						//Create data array under it.
						this.dataset [this.numDS].data = new Array ();
						//Get reference to child node.
						var arrLevel2Nodes : Array = arrLevel1Nodes [j].childNodes;
						//Iterate through all child-nodes of DATASET element
						//and search for SET node
						//Counter
						var setCount : Number = 0;
						for (k = 0; k < arrLevel2Nodes.length; k ++)
						{
							if (arrLevel2Nodes [k].nodeName.toUpperCase () == "SET")
							{
								//Set Node. So extract the data.
								//Update counter
								setCount ++;
								//Get reference to node.
								setNode = arrLevel2Nodes [k];
								//Get attributes
								var atts : Array;
								atts = this.getAttributesArray (setNode);
								//Now, get values.
								var setXV : Number = getFN (this.getSetValue (atts ["x"]) , setCount);
								var setYV : Number = this.getSetValue (atts ["y"]);
								var setZV : Number = getFN (this.getSetValue (atts ["z"]) , 0);
								//We do NOT unescape the link, as this will be done
								//in invokeLink method for the links that user clicks.
								var setLink : String = getFV (atts ["link"] , "");								
								var setShowValue : Number = getFN (atts ["showvalue"] , this.dataset [this.numDS].showValues);
								//individual bubble cosmetics
								var setColor : String = getFV (atts ["color"] , ((setZV < 0) ? this.params.negativeColor : this.dataset [this.numDS].color));
								var setAlpha : Number = getFN (atts ["alpha"] , this.dataset [this.numDS].alpha);
								var setName : String = getFV (atts ["name"] , setZV.toString ());
								var setToolText : String = getFV (atts ["tooltext"] , atts ["hovertext"] , atts ["name"]);
								//Store all these attributes as object.
								this.dataset [this.numDS].data [setCount] = this.returnDataAsObject (setXV, setYV, setZV, setName, setToolText, setLink, setShowValue, setColor, setAlpha);
							}
						}
						//Update global counter
						this.dataset [this.numDS].num = setCount;
						if (setCount > this.num)
						{
							this.num = setCount;
						}
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "STYLES")
					{
						//Styles Node - extract child nodes
						var arrStyleNodes : Array = arrLevel1Nodes [j].childNodes;
						//Parse the style nodes to extract style information
						super.parseStyleXML (arrStyleNodes);
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "HTRENDLINES" || arrLevel1Nodes [j].nodeName.toUpperCase () == "TRENDLINES")
					{
						//Trend lines node
						var arrTrendNodes : Array = arrLevel1Nodes [j].childNodes;
						//Parse the trend line nodes
						super.parseHTrendLineXML (arrTrendNodes);
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "VTRENDLINES")
					{
						//Vertical Trend lines node
						var arrTrendNodes : Array = arrLevel1Nodes [j].childNodes;
						//Parse the trend line nodes
						super.parseVTrendLineXML (arrTrendNodes);
					}
				}
			}
		}
		//Delete all temporary objects used for parsing XML Data document
		delete setNode;
		delete arrDocElement;
		delete arrLevel1Nodes;
		delete arrLevel2Nodes;
	}
	/**
	* parseAttributes method parses the attributes and stores them in
	* chart storage objects.
	* Starting ActionScript 2, the parsing of XML attributes have also
	* become case-sensitive. However, prior versions of FusionCharts
	* supported case-insensitive attributes. So we need to parse all
	* attributes as case-insensitive to maintain backward compatibility.
	* To do so, we first extract all attributes from XML, convert it into
	* lower case and then store it in an array. Later, we extract value from
	* this array.
	* @param	graphElement	XML Node containing the <graph> element
	*							and it's attributes
	*/
	private function parseAttributes (graphElement : XMLNode) : Void 
	{
		//Array to store the attributes
		var atts : Array = this.getAttributesArray (graphElement);
		//NOW IT'S VERY NECCESARY THAT WHEN WE REFERENCE THIS ARRAY
		//TO GET AN ATTRIBUTE VALUE, WE SHOULD PROVIDE THE ATTRIBUTE
		//NAME IN LOWER CASE. ELSE, UNDEFINED VALUE WOULD SHOW UP.
		//Extract attributes pertinent to this chart
		//Which palette to use?
		this.params.palette = getFN (atts ["palette"] , 1);
		//Whether to show about FusionCharts Menu Item - by default set to on
		this.params.showFCMenuItem = toBoolean(getFN (atts ["showfcmenuitem"] , 1));
		// ---------- PADDING AND SPACING RELATED ATTRIBUTES ----------- //
		//captionPadding = Space between caption/subcaption and canvas start Y
		this.params.captionPadding = getFN (atts ["captionpadding"] , 10);
		//Padding for x-axis name - to the right
		this.params.xAxisNamePadding = getFN (atts ["xaxisnamepadding"] , 5);
		//Padding for y-axis name - from top
		this.params.yAxisNamePadding = getFN (atts ["yaxisnamepadding"] , 5);
		//Y-Axis Values padding - Horizontal space between the axis edge and
		//y-axis values or trend line values (on left/right side).
		this.params.yAxisValuesPadding = getFN (atts ["yaxisvaluespadding"] , 2);
		//Label padding - Vertical space between the labels and canvas end position
		this.params.labelPadding = getFN (atts ["labelpadding"] , atts ["labelspadding"] , 3);
		//Padding of legend from right/bottom side of canvas
		this.params.legendPadding = getFN (atts ["legendpadding"] , 6);
		//Chart Margins - Empty space at the 4 sides
		this.params.chartLeftMargin = getFN (atts ["chartleftmargin"] , 15);
		this.params.chartRightMargin = getFN (atts ["chartrightmargin"] , 15);
		this.params.chartTopMargin = getFN (atts ["charttopmargin"] , 15);
		this.params.chartBottomMargin = getFN (atts ["chartbottommargin"] , 15);
		// -------------------------- HEADERS ------------------------- //
		//Chart Caption and sub Caption
		this.params.caption = getFV (atts ["caption"] , "");
		this.params.subCaption = getFV (atts ["subcaption"] , "");
		//X and Y Axis Name
		this.params.xAxisName = getFV (atts ["xaxisname"] , "");
		this.params.yAxisName = getFV (atts ["yaxisname"] , "");
		//Adaptive yMin - if set to true, the y min will be based on the values
		//provided. It won't be set to 0 in case of all positive values
		this.params.setAdaptiveYMin = toBoolean (getFN (atts ["setadaptiveymin"] , 0));
		// --------------------- CONFIGURATION ------------------------- //
		//The upper and lower limits of y and x axis
		this.params.yAxisMinValue = atts ["yaxisminvalue"];
		this.params.yAxisMaxValue = atts ["yaxismaxvalue"];
		//X-axis
		this.params.xAxisMinValue = atts ["xaxisminvalue"];
		this.params.xAxisMaxValue = atts ["xaxismaxvalue"];
		//Whether to set animation for entire chart.
		this.params.animation = toBoolean (getFN (atts ["animation"] , 1));
		//Whether to set the default chart animation
		this.params.defaultAnimation = toBoolean (getFN (atts ["defaultanimation"] , 1));
		//Configuration to set whether to show the labels
		this.params.showLabels = toBoolean (getFN (atts ["showlabels"] , atts ["shownames"] , 1));
		//Label Display Mode - WRAP, STAGGER, ROTATE or NONE
		this.params.labelDisplay = getFV (atts ["labeldisplay"] , "WRAP");
		//Remove spaces and capitalize
		this.params.labelDisplay = StringExt.removeSpaces (this.params.labelDisplay);
		this.params.labelDisplay = this.params.labelDisplay.toUpperCase ();
		//Option to show vertical x-axis labels
		this.params.rotateLabels = getFV (atts ["rotatelabels"] , atts ["rotatenames"]);
		//Whether to slant label (if rotated)
		this.params.slantLabels = toBoolean (getFN (atts ["slantlabels"] , atts ["slantlabel"] , 0));
		//Angle of rotation based on slanting
		this.config.labelAngle = (this.params.slantLabels == true) ? 315 : 270;
		//If rotateLabels has been explicitly specified, we assign ROTATE value to this.params.labelDisplay
		this.params.labelDisplay = (this.params.rotateLabels == "1") ? "ROTATE" : this.params.labelDisplay;
		//Step value for labels - i.e., show all labels or skip every x label
		this.params.labelStep = int (getFN (atts ["labelstep"] , 1));
		//Cannot be less than 1
		this.params.labelStep = (this.params.labelStep < 1) ? 1 : this.params.labelStep;
		//Number of stagger lines
		this.params.staggerLines = int (getFN (atts ["staggerlines"] , 2));
		//Cannot be less than 2
		this.params.staggerLines = (this.params.staggerLines < 2) ? 2 : this.params.staggerLines;
		//Configuration whether to show data values
		this.params.showValues = toBoolean (getFN (atts ["showvalues"] , 0));
		//Option to show/hide y-axis values
		this.params.showYAxisValues = getFN (atts ["showyaxisvalues"] , atts ["showyaxisvalue"] , 1);
		this.params.showLimits = toBoolean (getFN (atts ["showlimits"] , this.params.showYAxisValues));
		this.params.showDivLineValues = toBoolean (getFN (atts ["showdivlinevalue"] , atts ["showdivlinevalues"] , this.params.showYAxisValues));
		//Y-axis value step- i.e., show all y-axis or skip every x(th) value
		this.params.yAxisValuesStep = int (getFN (atts ["yaxisvaluesstep"] , atts ["yaxisvaluestep"] , 1));
		//Cannot be less than 1
		this.params.yAxisValuesStep = (this.params.yAxisValuesStep < 1) ? 1 : this.params.yAxisValuesStep;
		//Whether to automatically adjust div lines
		this.params.adjustDiv = toBoolean (getFN (atts ["adjustdiv"] , 1));
		//Whether to rotate y-axis name
		this.params.rotateYAxisName = toBoolean (getFN (atts ["rotateyaxisname"] , 1));
		//Max width to be alloted to y-axis name - No defaults, as it's calculated later.
		this.params.yAxisNameWidth = atts ["yaxisnamewidth"];
		//Click URL
		this.params.clickURL = getFV (atts ["clickurl"] , "");
		// ------------------------- COSMETICS -----------------------------//
		//Background properties - Gradient
		this.params.bgColor = getFV (atts ["bgcolor"] , this.defColors.get2DBgColor (this.params.palette));
		this.params.bgAlpha = getFV (atts ["bgalpha"] , this.defColors.get2DBgAlpha (this.params.palette));
		this.params.bgRatio = getFV (atts ["bgratio"] , this.defColors.get2DBgRatio (this.params.palette));
		this.params.bgAngle = getFV (atts ["bgangle"] , this.defColors.get2DBgAngle (this.params.palette));
		//Border Properties of chart
		this.params.showBorder = toBoolean (getFN (atts ["showborder"] , 1));
		this.params.borderColor = formatColor (getFV (atts ["bordercolor"] , this.defColors.get2DBorderColor (this.params.palette)));
		this.params.borderThickness = getFN (atts ["borderthickness"] , 1);
		this.params.borderAlpha = getFN (atts ["borderalpha"] , this.defColors.get2DBorderAlpha (this.params.palette));
		//Background swf
		this.params.bgSWF = getFV (atts ["bgswf"] , "");
		this.params.bgSWFAlpha = getFN (atts ["bgswfalpha"] , 100);
		//Canvas background properties - Gradient
		this.params.canvasBgColor = getFV (atts ["canvasbgcolor"] , this.defColors.get2DCanvasBgColor (this.params.palette));
		this.params.canvasBgAlpha = getFV (atts ["canvasbgalpha"] , this.defColors.get2DCanvasBgAlpha (this.params.palette));
		this.params.canvasBgRatio = getFV (atts ["canvasbgratio"] , this.defColors.get2DCanvasBgRatio (this.params.palette));
		this.params.canvasBgAngle = getFV (atts ["canvasbgangle"] , this.defColors.get2DCanvasBgAngle (this.params.palette));
		//Canvas Border properties
		this.params.canvasBorderColor = formatColor (getFV (atts ["canvasbordercolor"] , this.defColors.get2DCanvasBorderColor (this.params.palette)));
		this.params.canvasBorderThickness = getFN (atts ["canvasborderthickness"] , 2);
		this.params.canvasBorderAlpha = getFN (atts ["canvasborderalpha"] , this.defColors.get2DCanvasBorderAlpha (this.params.palette));
		//Legend properties
		this.params.showLegend = toBoolean (getFN (atts ["showlegend"] , 1));
		//Alignment position
		this.params.legendPosition = getFV (atts ["legendposition"] , "BOTTOM");
		//Legend position can be either RIGHT or BOTTOM -Check for it
		this.params.legendPosition = (this.params.legendPosition.toUpperCase () == "RIGHT") ? "RIGHT" : "BOTTOM";
		this.params.legendBorderColor = formatColor (getFV (atts ["legendbordercolor"] , this.defColors.get2DLegendBorderColor (this.params.palette)));
		this.params.legendBorderThickness = getFN (atts ["legendborderthickness"] , 1);
		this.params.legendBorderAlpha = getFN (atts ["legendborderalpha"] , 100);
		this.params.legendBgColor = getFV (atts ["legendbgcolor"] , this.defColors.get2DLegendBgColor (this.params.palette));
		this.params.legendBgAlpha = getFN (atts ["legendbgalpha"] , 100);
		this.params.legendShadow = toBoolean (getFN (atts ["legendshadow"] , 1));
		this.params.legendAllowDrag = toBoolean (getFN (atts ["legendallowdrag"] , 0));
		this.params.legendScrollBgColor = formatColor (getFV (atts ["legendscrollbgcolor"] , "CCCCCC"));
		this.params.legendScrollBarColor = formatColor (getFV (atts ["legendscrollbarcolor"] , this.params.legendBorderColor));
		this.params.legendScrollBtnColor = formatColor (getFV (atts ["legendscrollbtncolor"] , this.params.legendBorderColor));
		//Horizontal grid division Lines - Number, color, thickness & alpha
		//Necessarily need a default value for numDivLines.
		this.params.numDivLines = getFN (atts ["numdivlines"] , 4);
		this.params.divLineColor = formatColor (getFV (atts ["divlinecolor"] , this.defColors.get2DDivLineColor (this.params.palette)));
		this.params.divLineThickness = getFN (atts ["divlinethickness"] , 1);
		this.params.divLineAlpha = getFN (atts ["divlinealpha"] , this.defColors.get2DDivLineAlpha (this.params.palette));
		this.params.divLineIsDashed = toBoolean (getFN (atts ["divlineisdashed"] , 0));
		this.params.divLineDashLen = getFN (atts ["divlinedashlen"] , 4);
		this.params.divLineDashGap = getFN (atts ["divlinedashgap"] , 2);
		//Zero Plane properties
		this.params.showZeroPlane = toBoolean (getFN (atts ["showzeroplane"] , 1));
		this.params.zeroPlaneColor = formatColor (getFV (atts ["zeroplanecolor"] , this.params.divLineColor));
		this.params.zeroPlaneThickness = getFN (atts ["zeroplanethickness"] , 1);
		this.params.zeroPlaneAlpha = getFN (atts ["zeroplanealpha"] , this.params.divLineAlpha);
		//Alternating grid colors
		this.params.showAlternateHGridColor = toBoolean (getFN (atts ["showalternatehgridcolor"] , 1));
		this.params.alternateHGridColor = formatColor (getFV (atts ["alternatehgridcolor"] , this.defColors.get2DAltHGridColor (this.params.palette)));
		this.params.alternateHGridAlpha = getFN (atts ["alternatehgridalpha"] , this.defColors.get2DAltHGridAlpha (this.params.palette));
		//Tool Tip - Show/Hide, Background Color, Border Color, Separator Character
		this.params.showToolTip = toBoolean (getFN (atts ["showtooltip"] , atts ["showhovercap"] , 1));
		this.params.seriesNameInToolTip = toBoolean (getFN (atts ["seriesnameintooltip"] , 1));
		this.params.toolTipBgColor = formatColor (getFV (atts ["tooltipbgcolor"] , atts ["hovercapbgcolor"] , atts ["hovercapbg"] , this.defColors.get2DToolTipBgColor (this.params.palette)));
		this.params.toolTipBorderColor = formatColor (getFV (atts ["tooltipbordercolor"] , atts ["hovercapbordercolor"] , atts ["hovercapborder"] , this.defColors.get2DToolTipBorderColor (this.params.palette)));
		this.params.toolTipSepChar = getFV (atts ["tooltipsepchar"] , atts ["hovercapsepchar"] , ", ");
		//Font Properties
		this.params.baseFont = getFV (atts ["basefont"] , "Verdana");
		this.params.baseFontSize = getFN (atts ["basefontsize"] , 10);
		this.params.baseFontColor = formatColor (getFV (atts ["basefontcolor"] , this.defColors.get2DBaseFontColor (this.params.palette)));
		this.params.outCnvBaseFont = getFV (atts ["outcnvbasefont"] , this.params.baseFont);
		this.params.outCnvBaseFontSize = getFN (atts ["outcnvbasefontsize"] , this.params.baseFontSize);
		this.params.outCnvBaseFontColor = formatColor (getFV (atts ["outcnvbasefontcolor"] , this.params.baseFontColor));
		//Plot Properties
		this.params.plotFillAlpha = getFN (atts ["plotfillalpha"] , 100);
		this.params.showPlotBorder = getFN (atts ["showplotborder"] , 1);
		this.params.plotBorderColor = formatColor (getFV (atts ["plotbordercolor"] , "666666"));
		this.params.plotBorderThickness = getFN (atts ["plotborderthickness"] , 1);
		this.params.plotBorderAlpha = getFN (atts ["plotborderalpha"] , 95);
		//Bubble Properties
		this.params.use3DLighting = toBoolean (getFN (atts ["use3dlighting"] , atts ["is3d"] , 1));
		this.params.bubbleScale = Math.abs (getFN (atts ["bubblescale"] , 1));
		this.params.clipBubbles = toBoolean (getFN (atts ["clipbubbles"] , 1));
		this.params.negativeColor = formatColor (getFV (atts ["negativecolor"] , "ff0000"));
		// ------------------------- NUMBER FORMATTING ---------------------------- //
		//Option whether the format the number (using Commas)
		this.params.formatNumber = getFN (atts ["formatnumber"] , 1);
		//Option to format number scale
		this.params.formatNumberScale = getFN (atts ["formatnumberscale"] , 1);
		//Number Scales
		this.params.defaultNumberScale = getFV (atts ["defaultnumberscale"] , "");
		this.params.numberScaleUnit = getFV (atts ["numberscaleunit"] , "K,M");
		this.params.numberScaleValue = getFV (atts ["numberscalevalue"] , "1000,1000");
		//Number prefix and suffix
		//TODO: Escape them
		this.params.numberPrefix = getFV (atts ["numberprefix"] , "");
		this.params.numberSuffix = getFV (atts ["numbersuffix"] , "");
		//Decimal Separator Character
		this.params.decimalSeparator = getFV (atts ["decimalseparator"] , ".");
		//Thousand Separator Character
		this.params.thousandSeparator = getFV (atts ["thousandseparator"] , ",");
		//Input decimal separator and thousand separator. In some european countries,
		//commas are used as decimal separators and dots as thousand separators. In XML,
		//if the user specifies such values, it will give a error while converting to
		//number. So, we accept the input decimal and thousand separator from user, so that
		//we can covert it accordingly into the required format.
		this.params.inDecimalSeparator = getFV (atts ["indecimalseparator"] , "");
		this.params.inThousandSeparator = getFV (atts ["inthousandseparator"] , "");
		//Decimal Precision (number of decimal places to be rounded to)
		this.params.decimals = getFV (atts ["decimals"] , atts ["decimalprecision"]);
		//Force Decimal Padding
		this.params.forceDecimals = toBoolean (getFN (atts ["forcedecimals"] , 0));
		//y-Axis values decimals
		this.params.yAxisValueDecimals = getFV (atts ["yaxisvaluedecimals"] , atts ["yaxisvaluesdecimals"] , atts ["divlinedecimalprecision"] , atts ["limitsdecimalprecision"]);
	}
	/**
	* calculateAxisLimits method sets the axis limits for the chart.
	* It gets the minimum and maximum value specified in data and
	* based on that it calls super.getAxisLimits();
	*/
	private function calculateAxisLimits () : Void 
	{
		//Calculate for x-axis
		this.getXAxisLimits (this.getMaxXDataValue () , this.getMinXDataValue ());
		//Calculate for y-axis
		this.getYAxisLimits (this.getMaxYDataValue () , this.getMinYDataValue () , false, ! this.params.setAdaptiveYMin);
	}
	/**
	* setStyleDefaults method sets the default values for styles or
	* extracts information from the attributes and stores them into
	* style objects.
	*/
	private function setStyleDefaults () : Void 
	{
		//Default font object for Caption
		//-----------------------------------------------------------------//
		var captionFont = new StyleObject ();
		captionFont.name = "_SdCaptionFont";
		captionFont.align = "center";
		captionFont.valign = "top";
		captionFont.bold = "1";
		captionFont.font = this.params.outCnvBaseFont;
		captionFont.size = this.params.outCnvBaseFontSize;
		captionFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.CAPTION, captionFont, this.styleM.TYPE.FONT, null);
		delete captionFont;
		//-----------------------------------------------------------------//
		//Default font object for SubCaption
		//-----------------------------------------------------------------//
		var subCaptionFont = new StyleObject ();
		subCaptionFont.name = "_SdSubCaptionFont";
		subCaptionFont.align = "center";
		subCaptionFont.valign = "top";
		subCaptionFont.bold = "1";
		subCaptionFont.font = this.params.outCnvBaseFont;
		subCaptionFont.size = this.params.outCnvBaseFontSize;
		subCaptionFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.SUBCAPTION, subCaptionFont, this.styleM.TYPE.FONT, null);
		delete subCaptionFont;
		//-----------------------------------------------------------------//
		//Default font object for YAxisName
		//-----------------------------------------------------------------//
		var yAxisNameFont = new StyleObject ();
		yAxisNameFont.name = "_SdYAxisNameFont";
		yAxisNameFont.align = "center";
		yAxisNameFont.valign = "middle";
		yAxisNameFont.bold = "1";
		yAxisNameFont.font = this.params.outCnvBaseFont;
		yAxisNameFont.size = this.params.outCnvBaseFontSize;
		yAxisNameFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.YAXISNAME, yAxisNameFont, this.styleM.TYPE.FONT, null);
		delete yAxisNameFont;
		//-----------------------------------------------------------------//
		//Default font object for XAxisName
		//-----------------------------------------------------------------//
		var xAxisNameFont = new StyleObject ();
		xAxisNameFont.name = "_SdXAxisNameFont";
		xAxisNameFont.align = "center";
		xAxisNameFont.valign = "middle";
		xAxisNameFont.bold = "1";
		xAxisNameFont.font = this.params.outCnvBaseFont;
		xAxisNameFont.size = this.params.outCnvBaseFontSize;
		xAxisNameFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.XAXISNAME, xAxisNameFont, this.styleM.TYPE.FONT, null);
		delete xAxisNameFont;
		//-----------------------------------------------------------------//
		//Default font object for trend lines
		//-----------------------------------------------------------------//
		var trendFont = new StyleObject ();
		trendFont.name = "_SdTrendFontFont";
		trendFont.font = this.params.outCnvBaseFont;
		trendFont.size = this.params.outCnvBaseFontSize;
		trendFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.TRENDVALUES, trendFont, this.styleM.TYPE.FONT, null);
		this.styleM.overrideStyle (this.objects.VTRENDVALUES, trendFont, this.styleM.TYPE.FONT, null);
		delete trendFont;
		//-----------------------------------------------------------------//
		//Default font object for yAxisValues
		//-----------------------------------------------------------------//
		var yAxisValuesFont = new StyleObject ();
		yAxisValuesFont.name = "_SdYAxisValuesFont";
		yAxisValuesFont.align = "right";
		yAxisValuesFont.valign = "middle";
		yAxisValuesFont.font = this.params.outCnvBaseFont;
		yAxisValuesFont.size = this.params.outCnvBaseFontSize;
		yAxisValuesFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.YAXISVALUES, yAxisValuesFont, this.styleM.TYPE.FONT, null);
		delete yAxisValuesFont;
		//-----------------------------------------------------------------//
		//Default font object for DataLabels
		//-----------------------------------------------------------------//
		var dataLabelsFont = new StyleObject ();
		dataLabelsFont.name = "_SdDataLabelsFont";
		dataLabelsFont.align = "center";
		dataLabelsFont.valign = "bottom";
		dataLabelsFont.font = this.params.catFont;
		dataLabelsFont.size = this.params.catFontSize;
		dataLabelsFont.color = this.params.catFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.DATALABELS, dataLabelsFont, this.styleM.TYPE.FONT, null);
		delete dataLabelsFont;
		//-----------------------------------------------------------------//
		//Default font object for Legend
		//-----------------------------------------------------------------//
		var legendFont = new StyleObject ();
		legendFont.name = "_SdLegendFont";
		legendFont.font = this.params.outCnvBaseFont;
		legendFont.size = this.params.outCnvBaseFontSize;
		legendFont.color = this.params.outCnvBaseFontColor;
		legendFont.ishtml = 1;
		legendFont.leftmargin = 3;
		//Over-ride
		this.styleM.overrideStyle (this.objects.LEGEND, legendFont, this.styleM.TYPE.FONT, null);
		delete legendFont;
		//-----------------------------------------------------------------//
		//Default font object for DataValues
		//-----------------------------------------------------------------//
		var dataValuesFont = new StyleObject ();
		dataValuesFont.name = "_SdDataValuesFont";
		dataValuesFont.align = "center";
		dataValuesFont.valign = "middle";
		dataValuesFont.font = this.params.baseFont;
		dataValuesFont.size = this.params.baseFontSize;
		dataValuesFont.color = this.params.baseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.DATAVALUES, dataValuesFont, this.styleM.TYPE.FONT, null);
		delete dataValuesFont;
		//-----------------------------------------------------------------//
		//Default font object for ToolTip
		//-----------------------------------------------------------------//
		var toolTipFont = new StyleObject ();
		toolTipFont.name = "_SdToolTipFont";
		toolTipFont.font = this.params.baseFont;
		toolTipFont.size = this.params.baseFontSize;
		toolTipFont.color = this.params.baseFontColor;
		toolTipFont.bgcolor = this.params.toolTipBgColor;
		toolTipFont.bordercolor = this.params.toolTipBorderColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.TOOLTIP, toolTipFont, this.styleM.TYPE.FONT, null);
		delete toolTipFont;
		//-----------------------------------------------------------------//
		//Default Effect (Shadow) object for Legend
		//-----------------------------------------------------------------//
		if (this.params.legendShadow)
		{
			var legendShadow = new StyleObject ();
			legendShadow.name = "_SdLegendShadow";
			legendShadow.distance = 2;
			legendShadow.angle = 45;
			legendShadow.alpha = 90;
			//Over-ride
			this.styleM.overrideStyle (this.objects.LEGEND, legendShadow, this.styleM.TYPE.SHADOW, null);
			delete legendShadow;
		}
		//-----------------------------------------------------------------//
		//Default Animation object for DataPlot (if required)
		//-----------------------------------------------------------------//
		if (this.params.defaultAnimation)
		{
			//We need three animation objects.
			//1. XScale for data plot
			var dataPlotAnim = new StyleObject ();
			dataPlotAnim.name = "_SdDataPlotAnimXScale";
			dataPlotAnim.param = "_xscale";
			dataPlotAnim.easing = "regular";
			dataPlotAnim.wait = 0;
			dataPlotAnim.start = 0;
			dataPlotAnim.duration = 0.7;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOT, dataPlotAnim, this.styleM.TYPE.ANIMATION, "_xscale");
			delete dataPlotAnim;
			//2. YScale for data plot
			var dataPlotAnimY = new StyleObject ();
			dataPlotAnimY.name = "_SdDataPlotAnimYScale";
			dataPlotAnimY.param = "_yscale";
			dataPlotAnimY.easing = "regular";
			dataPlotAnimY.start = 0;
			dataPlotAnimY.duration = 0.7;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOT, dataPlotAnimY, this.styleM.TYPE.ANIMATION, "_yscale");
			delete dataPlotAnimY;
			//3. Alpha effect for bubbles
			var bubblesAnim = new StyleObject ();
			bubblesAnim.name = "_SdDataBubbleAnim";
			bubblesAnim.param = "_alpha";
			bubblesAnim.easing = "regular";
			bubblesAnim.wait = 0;
			bubblesAnim.start = 0;
			bubblesAnim.duration = 0.5;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOT, bubblesAnim, this.styleM.TYPE.ANIMATION, "_alpha");
			delete bubblesAnim;
		}
		//-----------------------------------------------------------------//
		
	}
	/**
	* calculatePoints method calculates the various points on the chart.
	*/
	private function calculatePoints ()
	{
		//Loop variable
		var i : Number;
		var j : Number;
		//Format all the numbers on the chart and store their display values
		//We format and store here itself, so that later, whenever needed,
		//we just access displayValue instead of formatting once again.
		//Also set tool tip text values
		var toolText : String;
		for (i = 1; i <= this.numDS; i ++)
		{
			for (j = 1; j <= this.dataset [i].num; j ++)
			{
				//Format and store
				this.dataset [i].data [j].displayValue = formatNumber (this.dataset [i].data [j].yv, this.params.formatNumber, this.params.decimals, this.params.forceDecimals, this.params.formatNumberScale, this.params.defaultNumberScale, this.config.nsv, this.config.nsu, this.params.numberPrefix, this.params.numberSuffix);
				//Tool tip text.
				//Preferential Order - Set Tool Text (No concatenation) > SeriesName + Cat Name + Value
				if (this.dataset [i].data [j].toolText == undefined || this.dataset [i].data [j].toolText == "")
				{
					//If the tool tip text is not already defined
					//If labels have been defined
					toolText = (this.params.seriesNameInToolTip && this.dataset [i].seriesName != "") ? (this.dataset [i].seriesName + this.params.toolTipSepChar) : "";
					toolText = toolText + this.dataset [i].data [j].xv + this.params.toolTipSepChar;
					toolText = toolText + this.dataset [i].data [j].displayValue + this.params.toolTipSepChar;
					toolText = toolText + this.dataset [i].data [j].zv;
					this.dataset [i].data [j].toolText = toolText;
				}
			}
		}
		//Calculate x-position of categories
		for (i = 1; i <= this.numCat; i ++)
		{
			//If categories is within the valid range
			if (this.categories [i].xv < this.config.xMin || this.categories [i].xv > this.config.xMax)
			{
				this.categories [i].isValid = false;
			}
			this.categories [i].x = this.getAxisPosition (this.categories [i].xv, this.config.xMax, this.config.xMin, this.elements.canvas.x, this.elements.canvas.toX, false, 0);
		}
		//to calculate the limits of z-values of the overall chart
		this.getZLimits ();
		//We now need to calculate the position of points on the chart.
		for (i = 1; i <= this.numDS; i ++)
		{
			//Now, store the positions of the points
			for (j = 1; j <= this.dataset [i].num; j ++)
			{
				this.dataset [i].data [j].x = this.getAxisPosition (this.dataset [i].data [j].xv, this.config.xMax, this.config.xMin, this.elements.canvas.x, this.elements.canvas.toX, false, 0);
				//Set the y position
				this.dataset [i].data [j].y = this.getAxisPosition (this.dataset [i].data [j].yv, this.config.yMax, this.config.yMin, this.elements.canvas.y, this.elements.canvas.toY, true, 0);
				// set the bubble radius
				this.dataset [i].data [j].radius = this.getBubbleRadius (this.dataset [i].data [j].zv, this.elements.canvas.w, this.elements.canvas.h);
			}
		}
		//method called to set the level of the bubble movieclips w.r.t. their radius ... lower the radius, lower is its levelor depth.
		this.sortZ ();
	}
	/**
	* allotDepths method allots the depths for various chart objects
	* to be rendered. We do this before hand, so that we can later just
	* go on rendering chart objects, without swapping.
	*/
	private function allotDepths () : Void 
	{
		//Background
		this.dm.reserveDepths ("BACKGROUND", 1);
		//Click URL Handler
		this.dm.reserveDepths ("CLICKURLHANDLER", 1);
		//Background SWF
		this.dm.reserveDepths ("BGSWF", 1);
		//Canvas
		this.dm.reserveDepths ("CANVAS", 1);
		//If horizontal grid is to be shown
		if (this.params.showAlternateHGridColor)
		{
			this.dm.reserveDepths ("HGRID", Math.ceil ((this.divLines.length + 1) / 2));
		}
		//Div Lines and their labels
		this.dm.reserveDepths ("DIVLINES", (this.divLines.length * 2));
		//Vertical div lines
		this.dm.reserveDepths ("VLINES", this.numCat);
		//Zero Plane
		this.dm.reserveDepths ("ZEROPLANE", 2);
		//Caption
		this.dm.reserveDepths ("CAPTION", 1);
		//Sub-caption
		this.dm.reserveDepths ("SUBCAPTION", 1);
		//X-Axis Name
		this.dm.reserveDepths ("XAXISNAME", 1);
		//Y-Axis Name
		this.dm.reserveDepths ("YAXISNAME", 1);
		//Vertical trend lines
		this.dm.reserveDepths ("VTRENDLINES", this.numVTrendLines);
		this.dm.reserveDepths ("VTRENDVALUES", this.numVTrendLines);
		//Horizontal Trend lines below plot (lines and their labels)
		this.dm.reserveDepths ("TRENDLINESBELOW", this.numTrendLinesBelow);
		this.dm.reserveDepths ("TRENDVALUESBELOW", this.numTrendLinesBelow);
		//Data Labels
		this.dm.reserveDepths ("DATALABELS", this.numCat);
		//Canvas Border
		this.dm.reserveDepths ("CANVASBORDER", 1);
		//Bubbles
		this.dm.reserveDepths ("DATAPLOT", this.num * this.numDS);
		//bubble Chart mask
		this.dm.reserveDepths ("MASK", 1);
		//Horizontal Trend lines below plot (lines and their labels)
		this.dm.reserveDepths ("TRENDLINESABOVE", (this.numTrendLines - this.numTrendLinesBelow));
		this.dm.reserveDepths ("TRENDVALUESABOVE", (this.numTrendLines - this.numTrendLinesBelow));
		//Data Values
		this.dm.reserveDepths ("DATAVALUES", this.num * this.numDS);
		//Legend
		this.dm.reserveDepths ("LEGEND", 1);
	}
	/**
	* sortZ is the method to sort bubbles of the whole chart
	* w.r.t. the bubble radius in such a way that bubbles with
	* smaller radius is above those with larger radii.
	*/
	private function sortZ () : Void 
	{
		var radius : Number, strId : String;
		// a temporary container created
		var arrDepth : Array = new Array ();
		//iterated to get the radius and their address ids in the temp array encapsulated in an object
		// looping over sets
		for (var i = 1; i <= this.numDS; ++ i)
		{
			// looping inside a set
			for (var j = 1; j < this.dataset [i].data.length; ++ j)
			{
				// getting the radius
				radius = this.dataset [i].data [j].radius;
				// storing in temp array as an object with properties
				arrDepth.push (
				{
					setId : i, bubbleId : j, radius : radius
				});
			}
		}
		// sorting the temp array numerically and in a descending order
		arrDepth.sortOn ("radius", 16 | 2);
		//adding the depth attribute in this.dataset[setId].data to be used during drawing bubbles
		for (var v in arrDepth)
		{
			//depth stored as number
			this.dataset [arrDepth [v].setId].data [arrDepth [v].bubbleId].depth = Number (v);
		}
	}
	/**
	* getZLimits is the method to evaluate the limits of the
	* z-values of the entire data sets.
	*/
	private function getZLimits () : Void 
	{
		var dataZ : Number;
		// storing the minimum value possible in flash
		var maxZ : Number = Number.MIN_VALUE;
		// storing the maximum value possible in flash
		var minZ : Number = Number.MAX_VALUE;
		//looping to get the maximum and minimum vaues of all the z-values in the entire chart
		// looping over datasets
		for (var i = 1; i <= this.numDS; ++ i)
		{
			// looping inside dataset
			for (var j = 1; j < this.dataset [i].data.length; ++ j)
			{
				// storing the absolute value of the z-value (since this will be used to calculate radius which can't be negative)
				dataZ = Math.abs (this.dataset [i].data [j].zv);
				// getting the larger vaue
				maxZ = (dataZ > maxZ) ? dataZ : maxZ;
				// getting the smaller vaue
				minZ = (dataZ < minZ) ? dataZ : minZ;
			}
		}
		// storing the limiting z-values in config
		this.config.maxZ = maxZ;
		this.config.minZ = minZ;
	}
	/**
	* getBubbleRadius is the method to calculate and return
	* the actual pixel radius of an individual bubble.
	* @param	zParam			z-value of the bubble
	* @param	canvasWidth		width of canvas
	* @param	canvasHeight	height of canvas
	* @return					radius as number
	*/
	private function getBubbleRadius (zParam : Number, canvasWidth : Number, canvasHeight : Number) : Number 
	{
		// storing the absolute value of the z-value (since this will be used to calculate radius which can't be negative)
		zParam = Math.abs (zParam);
		// to have diameter of the largest bubble as 25% of the smaller of the two dimensions of canvas
		var radiusLimit : Number = ((canvasWidth > canvasHeight) ? canvasHeight : canvasWidth) / 8;
		// taking square root of the z-value of the bubble
		var sqrtBubbleZ : Number = Math.sqrt (zParam);
		// taking square root of the maximum z-value of all bubbles
		var sqrtMaxZ : Number = Math.sqrt (this.config.maxZ);
		// calculating radius with scaling
		var radius : Number = Math.round (sqrtBubbleZ * radiusLimit / sqrtMaxZ) * this.params.bubbleScale;
		// radius returned
		return radius;
	}
	//--------------- VISUAL RENDERING METHODS -------------------------//
	/**
	* drawHeaders method renders the following on the chart:
	* CAPTION, SUBCAPTION, XAXISNAME, YAXISNAME
	*/
	private function drawHeaders ()
	{
		//Render caption
		if (this.params.caption != "")
		{
			var captionStyleObj : Object = this.styleM.getTextStyle (this.objects.CAPTION);
			captionStyleObj.align = "center";
			captionStyleObj.vAlign = "bottom";
			var captionObj : Object = createText (false, this.params.caption, this.cMC, this.dm.getDepth ("CAPTION") , this.elements.canvas.x + (this.elements.canvas.w / 2) , this.params.chartTopMargin, 0, captionStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (captionObj.tf, this.objects.CAPTION, this.macro, this.elements.canvas.x + (this.elements.canvas.w / 2) - (this.elements.caption.w / 2) , 0, this.params.chartTopMargin, 0, 100, null, null, null);
			}
			//Apply filters
			this.styleM.applyFilters (captionObj.tf, this.objects.CAPTION);
			//Delete
			delete captionObj;
			delete captionStyleObj;
		}
		//Render sub caption
		if (this.params.subCaption != "")
		{
			var subCaptionStyleObj : Object = this.styleM.getTextStyle (this.objects.SUBCAPTION);
			subCaptionStyleObj.align = "center";
			subCaptionStyleObj.vAlign = "top";
			var subCaptionObj : Object = createText (false, this.params.subCaption, this.cMC, this.dm.getDepth ("SUBCAPTION") , this.elements.canvas.x + (this.elements.canvas.w / 2) , this.elements.canvas.y - this.params.captionPadding, 0, subCaptionStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (subCaptionObj.tf, this.objects.SUBCAPTION, this.macro, this.elements.canvas.x + (this.elements.canvas.w / 2) - (this.elements.subCaption.w / 2) , 0, this.elements.canvas.y - this.params.captionPadding - this.elements.subCaption.h, 0, 100, null, null, null);
			}
			//Apply filters
			this.styleM.applyFilters (subCaptionObj.tf, this.objects.SUBCAPTION);
			//Delete
			delete subCaptionObj;
			delete subCaptionStyleObj;
		}
		//Render x-axis name
		if (this.params.xAxisName != "")
		{
			var xAxisNameStyleObj : Object = this.styleM.getTextStyle (this.objects.XAXISNAME);
			xAxisNameStyleObj.align = "center";
			xAxisNameStyleObj.vAlign = "bottom";
			var xAxisNameObj : Object = createText (false, this.params.xAxisName, this.cMC, this.dm.getDepth ("XAXISNAME") , this.elements.canvas.x + (this.elements.canvas.w / 2) , this.elements.canvas.toY + this.params.labelPadding + this.config.labelAreaHeight + this.params.xAxisNamePadding + this.config.vTrendHeight, 0, xAxisNameStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (xAxisNameObj.tf, this.objects.XAXISNAME, this.macro, this.elements.canvas.x + (this.elements.canvas.w / 2) - (this.elements.subCaption.w / 2) , 0, this.elements.canvas.toY + this.config.labelAreaHeight + this.params.xAxisNamePadding, 0, 100, null, null, null);
			}
			//Apply filters
			this.styleM.applyFilters (xAxisNameObj.tf, this.objects.XAXISNAME);
			//Delete
			delete xAxisNameObj;
			delete xAxisNameStyleObj;
		}
		//Render y-axis name
		if (this.params.yAxisName != "")
		{
			var yAxisNameStyleObj : Object = this.styleM.getTextStyle (this.objects.YAXISNAME);
			//Set alignment parameters
			yAxisNameStyleObj.align = "left";
			yAxisNameStyleObj.vAlign = "middle";
			//If the name is to be rotated
			if (this.params.rotateYAxisName)
			{
				//Set font as the embedded font
				yAxisNameStyleObj.font = _embeddedFont;
				//Set bold/italic to false.
				yAxisNameStyleObj.bold = false;
				yAxisNameStyleObj.italic = false;
				var yAxisNameObj : Object = createText (false, this.params.yAxisName, this.cMC, this.dm.getDepth ("YAXISNAME") , this.params.chartLeftMargin, this.elements.canvas.y + (this.elements.canvas.h / 2) , 270, yAxisNameStyleObj, false, 0, 0);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.params.chartLeftMargin, 0, this.elements.canvas.y + (this.elements.canvas.h / 2) + (this.elements.yAxisName.h / 2) , 0, 100, null, null, null);
				}
			} else 
			{
				//We show horizontal name
				//Adding 1 to this.params.yAxisNameWidth and then passing to avoid line breaks
				var yAxisNameObj : Object = createText (false, this.params.yAxisName, this.cMC, this.dm.getDepth ("YAXISNAME") , this.params.chartLeftMargin, this.elements.canvas.y + (this.elements.canvas.h / 2) , 0, yAxisNameStyleObj, true, this.params.yAxisNameWidth + 1, this.elements.canvas.h);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.params.chartLeftMargin, 0, yAxisNameObj.tf._y, 0, 100, null, null, null);
				}
			}
			//Apply filters
			this.styleM.applyFilters (yAxisNameObj.tf, this.objects.YAXISNAME);
			//Delete
			delete yAxisNameObj;
			delete yAxisNameStyleObj;
		}
		//Clear Interval
		clearInterval (this.config.intervals.headers);
	}
	/**
	* drawLabels method draws the x-axis labels based on the parameters.
	*/
	private function drawLabels ()
	{
		var labelObj : Object;
		var labelStyleObj : Object = this.styleM.getTextStyle (this.objects.DATALABELS);
		var labelYShift : Number;
		var staggerCycle : Number = 0;
		var staggerAddFn : Number = 1;
		var depth : Number = this.dm.getDepth ("DATALABELS");
		var i : Number;
		for (i = 1; i <= this.numCat; i ++)
		{
			//If the label is to be shown
			if (this.categories [i].isValid && this.categories [i].showLabel)
			{
				if (this.params.labelDisplay == "ROTATE")
				{
					//Set style bold/italic to false and font to embedded font
					labelStyleObj.font = _embeddedFont;
					labelStyleObj.bold = false;
					labelStyleObj.italic = false;
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					//Create text box and get height
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding, this.config.labelAngle, labelStyleObj, false, 0, 0);
				} else if (this.params.labelDisplay == "WRAP")
				{
					//Case 2 (WRAP)
					//Set alignment
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding, 0, labelStyleObj, true, this.config.wrapLabelWidth, this.config.wrapLabelHeight);
				} else if (this.params.labelDisplay == "STAGGER")
				{
					//Case 3 (Stagger)
					//Set alignment
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					//Need to get cyclic position for staggered textboxes
					//Matrix formed is of 2*this.params.staggerLines - 2 rows
					var pos : Number = i % (2 * this.params.staggerLines - 2);
					//Last element needs to be reset
					pos = (pos == 0) ? (2 * this.params.staggerLines - 2) : pos;
					//Cyclic iteration
					pos = (pos > this.params.staggerLines) ? (this.params.staggerLines - (pos % this.params.staggerLines)) : pos;
					//Get position to 0 base
					pos --;
					//Shift accordingly
					var labelYShift : Number = this.config.maxLabelHeight * pos;
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding + labelYShift, 0, labelStyleObj, false, 0, 0);
				} else 
				{
					//Render normal label
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding, 0, labelStyleObj, false, 0, 0);
				}
				//Apply filter
				this.styleM.applyFilters (labelObj.tf, this.objects.DATALABELS);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (labelObj.tf, this.objects.DATALABELS, this.macro, labelObj.tf._x, 0, labelObj.tf._y, 0, 100, null, null, null);
				}
				//Increase depth
				depth ++;
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.labels);
	}
	/**
	* drawBubbleChart method draws the bubbles on the chart
	*/
	private function drawBubbleChart () : Void 
	{
		//Variables
		var bubbleMC : MovieClip;
		// getting level depth of the movieclip holding the bubbleChart
		var chartDepth : Number = this.dm.getDepth ("DATAPLOT");
		// movieclip created to draw the bubbleChart in
		var mcChart : MovieClip = this.cMC.createEmptyMovieClip ("ChartHolder", chartDepth);
		var i : Number, j : Number;
		//Create function storage containers for Delegate functions
		var fnRollOver : Function, fnClick : Function;
		var depth : Number;
		//Iterate through all columns
		for (i = 1; i <= this.numDS; i ++)
		{
			for (j = 1; j <= this.dataset [i].num; j ++)
			{
				//If defined
				if (this.dataset [i].data [j].isDefined)
				{
					depth = this.dataset [i].data [j].depth;
					//Create an empty movie clip for this bubble
					bubbleMC = mcChart.createEmptyMovieClip ("Bubble_" + i + "_" + j, depth);
					//Set the line style and fill
					bubbleMC.lineStyle (this.dataset [i].plotBorderThickness, parseInt (this.dataset [i].plotBorderColor, 16) , this.dataset [i].plotBorderAlpha);
					// getting bubble color as string
					var bubbleFillColor : String = this.dataset [i].data [j].color;
					// getting bubble alpha
					var bubbleFillAlpha : Number = this.dataset [i].data [j].alpha;
					// if bubble is to be shown with 3D effect
					if (this.params.use3DLighting)
					{
						// getting radius of the bubble
						var r : Number = this.dataset [i].data [j].radius;
						// getting a darker color for shadow
						var shadowColor : Number = ColorExt.getDarkColor (bubbleFillColor, 0.7);
						// getting a lighter color for highlight
						var highLightColor : Number = ColorExt.getLightColor (bubbleFillColor, 0.7);
						// setting params for gradient
						var strFillType : String = "radial";
						var arrColor : Array = [highLightColor, shadowColor];
						var arrAlpha : Array = [bubbleFillAlpha, bubbleFillAlpha];
						var arrRatio : Array = [0, 255];
						// x and y are manipulated to have the highlight in the upper left side of the bubbles
						var objMatrix : Object = {
							matrixType : "box", x : - r * 1.2, y : - r * 1.2, w : 2 * r, h : 2 * r, r : 0
						};
						// set gradient
						bubbleMC.beginGradientFill (strFillType, arrColor, arrAlpha, arrRatio, objMatrix);
					} else 
					{
						// set fill
						bubbleMC.beginFill (parseInt (bubbleFillColor, 16) , 100);
					}
					//Draw the bubble
					this.drawBubble (bubbleMC, this.dataset [i].data [j].radius);
					//ending fill
					bubbleMC.endFill ();
					//Set the x and y Position
					bubbleMC._x = this.dataset [i].data [j].x;
					bubbleMC._y = this.dataset [i].data [j].y;
					//Apply animation
					if (this.params.animation)
					{
						this.styleM.applyAnimation (bubbleMC, this.objects.DATAPLOT, this.macro, bubbleMC._x, 0, bubbleMC._y, 0, 100, 100, 100, null);
					}
					//Apply filters
					this.styleM.applyFilters (bubbleMC, this.objects.DATAPLOT);
					//Event handlers for tool tip
					if (this.params.showToolTip)
					{
						//Create Delegate for roll over function columnOnRollOver
						fnRollOver = Delegate.create (this, dataOnRollOver);
						//Set the index
						fnRollOver.dsindex = i;
						fnRollOver.index = j;
						//Assing the delegates to movie clip handler
						bubbleMC.onRollOver = fnRollOver;
						//Set roll out and mouse move too.
						bubbleMC.onRollOut = bubbleMC.onReleaseOutside = Delegate.create (this, dataOnRollOut);
						bubbleMC.onMouseMove = Delegate.create (this, dataOnMouseMove);
					}
					//Click handler for links - only if link for this bubble has been defined and click URL
					//has not been defined.
					if (this.dataset [i].data [j].link != "" && this.dataset [i].data [j].link != undefined && this.params.clickURL == "")
					{
						//Create delegate function
						fnClick = Delegate.create (this, dataOnClick);
						//Set index
						fnClick.dsindex = i;
						fnClick.index = j;
						//Assign
						bubbleMC.onRelease = fnClick;
					} else 
					{
						//Do not use hand cursor
						bubbleMC.useHandCursor = (this.params.clickURL == "") ? false : true;
					}
				}
			}
		}
		// if clipping of bubbles outside canvas is required
		if (this.params.clipBubbles)
		{
			// getting mask mc depth
			var maskDepth : Number = this.dm.getDepth ("MASK");
			// movieclip created for drawing mask rectangle
			var mcMask : MovieClip = this.cMC.createEmptyMovieClip ("mcChartMask", maskDepth);
			// set fill
			mcMask.beginFill (0xff0000, 100);
			// draw rectangle fitting the canvas exactly
			mcMask.moveTo (this.elements.canvas.x, this.elements.canvas.y);
			mcMask.lineTo (this.elements.canvas.x, this.elements.canvas.toY);
			mcMask.lineTo (this.elements.canvas.toX, this.elements.canvas.toY);
			mcMask.lineTo (this.elements.canvas.toX, this.elements.canvas.y);
			mcMask.lineTo (this.elements.canvas.x, this.elements.canvas.y);
			mcMask.endFill ();
			// mask applied to movieclip holding all the bubbles
			mcChart.setMask (mcMask);
		}
		//Clear interval
		clearInterval (this.config.intervals.bubbles);
	}
	/**
	* drawBubble method draws the individual bubbles on the chart.
	* @param	mcCanvas	movieclip to draw in
	* @param	radius		radius of the bubble in pixels
	*/
	private function drawBubble (mcCanvas : MovieClip, radius : Number) : Void 
	{
		//Refernce to MathExt.toNearestTwip method
		var toNT : Function = MathExt.toNearestTwip;
		var xend : Number, yend : Number, xcontrol : Number, ycontrol : Number;
		//Move to right side.
		mcCanvas.moveTo (radius, 0);
		//Circle drawn with given radius in 8 steps of 45 degrees circular curve in each
		for (var j : Number = 1; j <= 8; ++ j)
		{
			//Set end angle
			var t : Number = (Math.PI / 4) * j;
			//Get end co-ordinates
			xend = toNT (radius * Math.cos (t));
			yend = toNT (radius * Math.sin (t));
			//Control coordinates
			xcontrol = toNT (radius * Math.cos ((2 * ((Math.PI / 4) * (j - 1)) + (Math.PI / 4)) / 2) / Math.cos ((Math.PI / 4) / 2));
			ycontrol = toNT (radius * Math.sin ((2 * ((Math.PI / 4) * (j - 1)) + (Math.PI / 4)) / 2) / Math.cos ((Math.PI / 4) / 2));
			//Draw Curve
			mcCanvas.curveTo (xcontrol, ycontrol, xend, yend);
		}
	}
	/**
	* drawValues method draws the values on the chart.
	*/
	private function drawValues () : Void 
	{
		//Get value text style
		var valueStyleObj : Object = this.styleM.getTextStyle (this.objects.DATAVALUES);
		//Container object
		var valueObj : MovieClip;
		//Depth
		var depth : Number = this.dm.getDepth ("DATAVALUES");
		//Loop var
		var i : Number, j : Number;
		var yPos : Number;
		var align : String, vAlign : String;
		////Iterate through all points
		for (i = 1; i <= this.numDS; i ++)
		{
			for (j = 1; j <= this.dataset [i].num; j ++)
			{
				//If defined and value is to be shown
				if (this.dataset [i].data [j].isDefined && this.dataset [i].data [j].showValue)
				{
					//Set y position
					yPos = this.dataset [i].data [j].y;
					//Convey alignment to rendering object
					valueStyleObj.align = "center";
					valueStyleObj.vAlign = "middle";
					valueObj = createText (false, this.dataset [i].data [j].name, this.cMC, depth, this.dataset [i].data [j].x, yPos, 0, valueStyleObj, false, 0, 0);
					//Apply filter
					this.styleM.applyFilters (valueObj.tf, this.objects.DATAVALUES);
					//Apply animation
					if (this.params.animation)
					{
						this.styleM.applyAnimation (valueObj.tf, this.objects.DATAVALUES, this.macro, valueObj.tf._x, 0, valueObj.tf._y, 0, 100, null, null, null);
					}
					//Increase depth
					depth ++;
				}
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.dataValues);
	}
	/**
	* drawLegend method renders the legend
	*/
	private function drawLegend () : Void 
	{
		if (this.params.showLegend)
		{
			this.lgnd.render ();
			//Apply filter
			this.styleM.applyFilters (lgndMC, this.objects.LEGEND);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (lgndMC, this.objects.LEGEND, this.macro, null, 0, null, 0, 100, null, null, null);
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.legend);
	}
	/**
	* setContextMenu method sets the context menu for the chart.
	* For this chart, the context items are "Print Chart".
	*/
	private function setContextMenu () : Void 
	{
		var chartMenu : ContextMenu = new ContextMenu ();
		chartMenu.hideBuiltInItems ();
		//Create a print chart contenxt menu item
		var printCMI : ContextMenuItem = new ContextMenuItem ("Print Chart", Delegate.create (this, printChart));
		//Push print item.
		chartMenu.customItems.push (printCMI);
		if (this.params.showFCMenuItem){
			//Push "About FusionCharts" Menu Item
			chartMenu.customItems.push(super.returnAbtMenuItem());		
		}
		//Assign the menu to cMC movie clip
		this.cMC.menu = chartMenu;
	}
	// -------------------- EVENT HANDLERS --------------------//
	/**
	* dataOnRollOver is the delegat-ed event handler method that'll
	* be invoked when the user rolls his mouse over a bubble.
	* This function is invoked, only if the tool tip is to be shown.
	* Here, we show the tool tip.
	*/
	private function dataOnRollOver () : Void 
	{
		//Index of data is stored in arguments.caller.index
		var dsindex : Number = arguments.caller.dsindex;
		var index : Number = arguments.caller.index;
		//Set tool tip text
		this.tTip.setText (this.dataset [dsindex].data [index].toolText);
		//Show the tool tip
		this.tTip.show ();
	}
	/**
	* dataOnRollOut method is invoked when the mouse rolls out
	* of bubble. We just hide the tool tip here.
	*/
	private function dataOnRollOut () : Void 
	{
		//Hide the tool tip
		this.tTip.hide ();
	}
	/*
	* dataOnMouseMove is called when the mouse position has changed
	* over column. We reposition the tool tip.
	*/
	private function dataOnMouseMove () : Void
	{
		//Reposition the tool tip only if it's in visible state
		if (this.tTip.visible ())
		{
			this.tTip.rePosition ();
		}
	}
	/**
	* dataOnClick is invoked when the user clicks on a bubble (if link
	* has been defined). We invoke the required link.
	*/
	private function dataOnClick () : Void 
	{
		//Index of column is stored in arguments.caller.index
		var dsindex : Number = arguments.caller.dsindex;
		var index : Number = arguments.caller.index;
		//Invoke the link
		super.invokeLink (this.dataset [dsindex].data [index].link);
	}
	/**
	* reInit method re-initializes the chart. This method is basically called
	* when the user changes chart data through JavaScript. In that case, we need
	* to re-initialize the chart, set new XML data and again render.
	*/
	public function reInit () : Void 
	{
		//Invoke super class's reInit
		super.reInit ();
	}
	/**
	* remove method removes the chart by clearing the chart movie clip
	* and removing any listeners.
	*/
	public function remove () : Void 
	{
		super.remove ();
	}
}
